package com.xinggq.common.utils;

import com.xinggq.common.exception.IdGeneratorException;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 分布式ID生成器 - 基于雪花算法(Snowflake)
 * 
 * <p>雪花算法生成的ID结构：</p>
 * <pre>
 * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
 * |   |                                             |   |       |       |
 * |   |--- 41位时间戳(毫秒级)                        |   |       |       |--- 12位序列号
 * |                                                 |   |       |--- 5位机器ID
 * |                                                 |   |--- 5位数据中心ID
 * |--- 1位符号位(固定为0)                           |--- 1位未使用
 * </pre>
 * 
 * <p>特点：</p>
 * <ul>
 *   <li>生成的ID为64位长整型</li>
 *   <li>时间有序，同一毫秒内生成的ID递增</li>
 *   <li>支持分布式环境，不同机器生成的ID不重复</li>
 *   <li>高性能，单机每毫秒可生成4096个ID</li>
 * </ul>
 * 
 * @author xinggq
 * @since 1.0.0
 */
public class IdGenerator {
    
    /** 起始时间戳 (2023-01-01 00:00:00) */
    private static final long EPOCH = 1672531200000L;
    
    /** 机器ID所占的位数 */
    private static final long WORKER_ID_BITS = 5L;
    
    /** 数据中心ID所占的位数 */
    private static final long DATACENTER_ID_BITS = 5L;
    
    /** 序列号所占的位数 */
    private static final long SEQUENCE_BITS = 12L;
    
    /** 支持的最大机器ID，结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
    private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
    
    /** 支持的最大数据中心ID，结果是31 */
    private static final long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BITS);
    
    /** 生成序列的掩码，这里为4095 (0b111111111111=0xfff=4095) */
    private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);
    
    /** 机器ID向左移12位 */
    private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;
    
    /** 数据中心ID向左移17位(12+5) */
    private static final long DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
    
    /** 时间戳向左移22位(5+5+12) */
    private static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;
    
    /** 工作机器ID(0~31) */
    private final long workerId;
    
    /** 数据中心ID(0~31) */
    private final long datacenterId;
    
    /** 毫秒内序列(0~4095) */
    private long sequence = 0L;
    
    /** 上次生成ID的时间戳 */
    private long lastTimestamp = -1L;
    
    /** 线程安全锁 */
    private final ReentrantLock lock = new ReentrantLock();
    
    /** 默认实例 */
    private static volatile IdGenerator defaultInstance;
    
    /**
     * 构造函数
     * 
     * @param workerId     工作机器ID (0~31)
     * @param datacenterId 数据中心ID (0~31)
     */
    public IdGenerator(long workerId, long datacenterId) {
        if (workerId > MAX_WORKER_ID || workerId < 0) {
            throw new IdGeneratorException(
                String.format("Worker ID can't be greater than %d or less than 0", MAX_WORKER_ID));
        }
        if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0) {
            throw new IdGeneratorException(
                String.format("Datacenter ID can't be greater than %d or less than 0", MAX_DATACENTER_ID));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }
    
    /**
     * 获取默认实例（单例模式）
     * 使用默认的workerId=1, datacenterId=1
     * 
     * @return IdGenerator实例
     */
    public static IdGenerator getInstance() {
        if (defaultInstance == null) {
            synchronized (IdGenerator.class) {
                if (defaultInstance == null) {
                    defaultInstance = new IdGenerator(1L, 1L);
                }
            }
        }
        return defaultInstance;
    }
    
    /**
     * 获取自定义配置的实例
     * 
     * @param workerId     工作机器ID
     * @param datacenterId 数据中心ID
     * @return IdGenerator实例
     */
    public static IdGenerator getInstance(long workerId, long datacenterId) {
        return new IdGenerator(workerId, datacenterId);
    }
    
    /**
     * 生成下一个ID（线程安全）
     * 
     * @return 唯一ID
     */
    public long nextId() {
        lock.lock();
        try {
            long timestamp = timeGen();
            
            // 如果当前时间小于上一次ID生成的时间戳，说明系统时钟回退过这个时候应当抛出异常
            if (timestamp < lastTimestamp) {
                throw new IdGeneratorException(
                    String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", 
                        lastTimestamp - timestamp));
            }
            
            // 如果是同一时间生成的，则进行毫秒内序列
            if (lastTimestamp == timestamp) {
                sequence = (sequence + 1) & SEQUENCE_MASK;
                // 毫秒内序列溢出
                if (sequence == 0) {
                    // 阻塞到下一个毫秒，获得新的时间戳
                    timestamp = tilNextMillis(lastTimestamp);
                }
            } else {
                // 时间戳改变，毫秒内序列重置
                sequence = 0L;
            }
            
            // 上次生成ID的时间戳
            lastTimestamp = timestamp;
            
            // 移位并通过或运算拼到一起组成64位的ID
            return ((timestamp - EPOCH) << TIMESTAMP_LEFT_SHIFT)
                | (datacenterId << DATACENTER_ID_SHIFT)
                | (workerId << WORKER_ID_SHIFT)
                | sequence;
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 生成字符串格式的ID
     * 
     * @return 字符串ID
     */
    public String nextIdStr() {
        return String.valueOf(nextId());
    }
    
    /**
     * 阻塞到下一个毫秒，直到获得新的时间戳
     * 
     * @param lastTimestamp 上次生成ID的时间戳
     * @return 当前时间戳
     */
    protected long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }
    
    /**
     * 返回以毫秒为单位的当前时间
     * 
     * @return 当前时间(毫秒)
     */
    protected long timeGen() {
        return System.currentTimeMillis();
    }
    
    /**
     * 解析ID，获取ID的各个组成部分
     * 
     * @param id 要解析的ID
     * @return ID信息对象
     */
    public static IdInfo parseId(long id) {
        long timestamp = (id >> TIMESTAMP_LEFT_SHIFT) + EPOCH;
        long datacenterId = (id >> DATACENTER_ID_SHIFT) & MAX_DATACENTER_ID;
        long workerId = (id >> WORKER_ID_SHIFT) & MAX_WORKER_ID;
        long sequence = id & SEQUENCE_MASK;
        
        return new IdInfo(timestamp, datacenterId, workerId, sequence);
    }
    
    /**
     * ID信息类，用于存储解析后的ID各个组成部分
     */
    public static class IdInfo {
        private final long timestamp;
        private final long datacenterId;
        private final long workerId;
        private final long sequence;
        
        public IdInfo(long timestamp, long datacenterId, long workerId, long sequence) {
            this.timestamp = timestamp;
            this.datacenterId = datacenterId;
            this.workerId = workerId;
            this.sequence = sequence;
        }
        
        public long getTimestamp() {
            return timestamp;
        }
        
        public long getDatacenterId() {
            return datacenterId;
        }
        
        public long getWorkerId() {
            return workerId;
        }
        
        public long getSequence() {
            return sequence;
        }
        
        @Override
        public String toString() {
            return String.format("IdInfo{timestamp=%d, datacenterId=%d, workerId=%d, sequence=%d}", 
                timestamp, datacenterId, workerId, sequence);
        }
    }
    
    /**
     * 静态方法：生成ID（使用默认实例）
     * 
     * @return 唯一ID
     */
    public static long generateId() {
        return getInstance().nextId();
    }
    
    /**
     * 静态方法：生成字符串ID（使用默认实例）
     * 
     * @return 字符串ID
     */
    public static String generateIdStr() {
        return getInstance().nextIdStr();
    }
}